import random
from datetime import datetime
from flask import Flask
from flask_marshmallow import Marshmallow
from marshmallow import Schema,fields,validate,validates,validates_schema,ValidationError,post_load,pre_load
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]="mysql://root:1@127.0.0.1:3306/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy()
db.init_app(app)

ma = Marshmallow()
ma.init_app(app)

class User(db.Model):
    __tablename__ = "tb_user"
    id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    name = db.Column(db.String(255), index=True, comment="用户名")
    email = db.String(db.String(255))
    age = db.Column(db.Integer, comment="年龄")
    password = db.Column(db.String(255), comment="登录密码")
    mobile = db.Column(db.String(20), comment="手机号")

    def __repr__(self):
        return "<%s: %s>" % (self.__class__.__name__, self.name)

class UserSchema(Schema):
    name = fields.String()
    age = fields.Integer()
    email = fields.String()
    password = fields.Str() # 密码
    password2 = fields.String() # 确认密码
    mobile = fields.String(validate=validate.Regexp("^1[3-9]\d{9}$",error="手机号格式不正确!"))

    # 针对单个指定字段的值进行验证
    @validates("mobile")
    def validate_mobile(self,mobile):
        if(mobile == "13312345678"):
            raise ValidationError("手机号已经被注册！！")
        return mobile

    # 针对多个字段的验证
    @validates_schema
    def validate(self,data,**kwargs):
        if(data["password"] != data["password2"]):
            # 注意：验证失败以后，一定是raise抛出异常！！！不能是return!!!!
            raise ValidationError(field_name="password2",message="密码和确认密码不一致！")
        return data

    @post_load
    def post_load(self,data,**kwargs):
        """反序列化验证后的钩子方法"""
        print("num=%s" % self.num)
        print(self.context)
        del data["password2"] # 删除掉不必要的字段
        return User(**data)

@app.route("/")
def index():
    user_data = {"email":"xiaoming@qq.com","name": "小明", "age": 20,"password":"123456","mobile":"13312345671","password2": "123456"}

    num = random.randint(1,100)
    # 如果将来在开发中有部分数据需要传递到构造器中进行调用，可以在实例化构造器时通过context传递参数进行，在构造器内部通过self.context调用
    us = UserSchema(context={"num":num})
    # 如果将来在开发中有部分数据需要传递到构造器中进行调用，可以作为构造器对象的属性进行传递
    us.num = num
    # 反序列化
    instance = us.load(user_data)
    print(instance)
    return "hello"

if __name__ == '__main__':
    app.run(debug=True,host="0.0.0.0",port=5999)